﻿using CommData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using SocketSvrBiz;
using CommHelper;

namespace SHDServer
{
    public class AsyncSocketUserToken
    {
        #region 属性、事件

        public delegate void CloseSocket(AsyncSocketUserToken asyncSocketUserToken);

        private event CloseSocket m_EventCloseSocket = null;

        /// <summary>
        /// 关闭socket事件
        /// </summary>
        public event CloseSocket EventCloseSocket
        {
            add { m_EventCloseSocket += value; }
            remove { m_EventCloseSocket -= value; }
        }

        protected SocketAsyncEventArgs m_receiveEventArgs;
        private AccessInterface m_accInterface = new AccessInterface();
        private object m_server = null;
        private UserToken m_userToken = null;

        /// <summary>
        /// socket接受事件参数
        /// </summary>
        public SocketAsyncEventArgs ReceiveEventArgs
        {
            get { return m_receiveEventArgs; }
            set { m_receiveEventArgs = value; }
        }

        protected byte[] m_asyncReceiveBuffer;
        private int _requestlength = -1;
        private byte[] _rquestBodyBytes = null;
        private string _methodName;
        private int _errCode = 0;
        private uint _ipaddress = 0;

        /// <summary>
        /// 客户端地址
        /// </summary>
        private string m_clientAddressStr = string.Empty;

        private Socket m_connectSocket;

        /// <summary>
        /// 连接的socket对象
        /// </summary>
        public Socket ConnectSocket
        {
            get { return m_connectSocket; }
            set
            {
                m_connectSocket = value;
                if (m_connectSocket != null)
                {
                    m_connectSocket.SendTimeout = 2000;
                    IPEndPoint conpoint = ((IPEndPoint)ConnectSocket.RemoteEndPoint);
                    m_clientAddressStr = conpoint.Address + "_" + conpoint.Port;
                }
            }
        }

        /// <summary>
        /// 接收缓存
        /// </summary>
        private List<byte> m_listReceiveByte = new List<byte>();

        #endregion 属性、事件

        public AsyncSocketUserToken(object server, int asyncReceiveBufferSize)
        {
            m_server = server;
            m_receiveEventArgs = new SocketAsyncEventArgs();
            m_receiveEventArgs.UserToken = this;
            m_asyncReceiveBuffer = new byte[asyncReceiveBufferSize];
            m_receiveEventArgs.SetBuffer(m_asyncReceiveBuffer, 0, m_asyncReceiveBuffer.Length);
            m_receiveEventArgs.Completed += IO_Completed;
        }

        /// <summary>
        /// SocketAsyncEventArgs处理事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="asyncEventArgs"></param>
        private void IO_Completed(object sender, SocketAsyncEventArgs asyncEventArgs)
        {
            try
            {
                if (asyncEventArgs.LastOperation == SocketAsyncOperation.Receive)
                    ProcessReceive(asyncEventArgs);
            }
            catch (Exception E)
            {
                ConsoleHelper.WriteLine(E.Message);
                LogHelper.WriteErrorLog(E.Message);
                CloseClientSocket();
            }
        }

        /// <summary>
        /// 开启接受数据
        /// </summary>
        public void Receive()
        {
            try
            {
                if (ConnectSocket == null)
                {
                    return;
                }
                bool willRaiseEvent = ConnectSocket.ReceiveAsync(ReceiveEventArgs); //投递接收请求
                if (!willRaiseEvent)
                {
                    ProcessReceive(ReceiveEventArgs);
                }
            }
            catch (Exception e)
            {
                CloseClientSocket();
                LogHelper.WriteErrorLog("投递接收请求:" + e.Message);
            }
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="receiveEventArgs"></param>
        private void ProcessReceive(SocketAsyncEventArgs receiveEventArgs)
        {
            //  AsyncSocketUserToken userToken = receiveEventArgs.UserToken as AsyncSocketUserToken;
            if (ConnectSocket == null)
                return;
            if (receiveEventArgs.BytesTransferred > 0 && receiveEventArgs.SocketError == SocketError.Success)
            {
                lock (m_listReceiveByte)
                {
                    var tmpbytes = new byte[receiveEventArgs.BytesTransferred];
                    receiveEventArgs.Buffer.ToList().CopyTo(receiveEventArgs.Offset, tmpbytes, 0, receiveEventArgs.BytesTransferred);
                    m_listReceiveByte.AddRange(tmpbytes);
                    if (m_listReceiveByte.Count > 0)
                    {
                        OparReceive();
                    }
                }
                Receive();
            }
            else
            {
                CloseClientSocket();
            }
        }

        /// <summary>
        /// 接收数据处理
        /// </summary>
        private void OparReceive()
        {
            try
            {
                MessageStatus messagestatus = CommHelper.NetworkDataHelper.GetNetworkDataHelper.CheckData(m_listReceiveByte.ToArray(),
                    ref _requestlength, ref _rquestBodyBytes, ref _methodName, ref _errCode, ref _ipaddress);
                switch (messagestatus)
                {
                    case MessageStatus.Packet_Length_Error:
                        break;

                    case MessageStatus.Analysis_Error:
                        CloseClientSocket();
                        break;

                    case MessageStatus.Success:
                        m_listReceiveByte.RemoveRange(0, _requestlength + NetworkDataHelper.GetNetworkDataHelper.DataHeaderLength);
                        _requestlength = -1;
                        DealData(_methodName, _rquestBodyBytes);
                        if (m_listReceiveByte.Count > 0)
                        {
                            OparReceive();
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                CommHelper.ConsoleHelper.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 处理数据
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="requestBody"></param>
        private void DealData(string methodName, byte[] requestBody)
        {
            try
            {
                if (null == m_userToken)
                {
                    m_userToken = new UserToken();
                    m_userToken.sendResponse = SendData;
                    m_userToken.sendResponseAll = (m_server as SocketServer).SendResponseAll;
                }
                m_userToken.Ipaddress = _ipaddress;
                ConsoleHelper.WriteLine(string.Format("Recv from {0}, method: {1}, data len: {2}", m_clientAddressStr, methodName, requestBody.Length));

                m_accInterface.Dispatch(methodName, requestBody, m_userToken);
            }
            catch (Exception e)
            {
                LogHelper.WriteErrorLog(e.Message);
            }
        }

        /// <summary>
        /// 关闭socket并清理接口
        /// </summary>
        public void CloseClientSocket()
        {
            if (ConnectSocket == null)
                return;
            try
            {
                if (ConnectSocket.Connected)
                {
                    ConnectSocket.Shutdown(SocketShutdown.Both);
                }
            }
            catch (Exception E)
            {
                ConsoleHelper.WriteLine(E.Message);
                LogHelper.WriteErrorLog(E.Message);
            }
            finally
            {
                try
                {
                    _requestlength = -1;
                    ConnectSocket.Close();
                }
                catch (Exception E)
                {
                    LogHelper.WriteErrorLog(E.Message);
                }
                m_receiveEventArgs.AcceptSocket = null;
            }
            m_listReceiveByte.Clear();
            ConnectSocket = null; //释放引用，并清理缓存，包括释放协议对象等资源

            if (m_EventCloseSocket != null)
            {
                m_EventCloseSocket(this);
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="listsendarray"></param>
        public void SendData(byte[] listsendarray)
        {
            if (listsendarray == null)
                return;
            try
            {
                int sendDataLenther = 0;
                int bytelength = listsendarray.Length;
                while (sendDataLenther < bytelength)
                {
                    sendDataLenther += m_connectSocket.Send(listsendarray, sendDataLenther, bytelength - sendDataLenther, SocketFlags.None);
                }
            }
            catch (Exception E)
            {
                CloseClientSocket();
                ConsoleHelper.WriteLine(E.Message);
                LogHelper.WriteErrorLog(E.Message);
            }
        }
    }
}